package com.juc.concurrency.jucExample.lock;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * ReentrantLock之Condition
 * 运行方法 看效果，以及注释
 * 注释的1 2 3 4是执行顺序
 * 原理：协作过程是靠节点在在AQS等待队列以及ConditionQueue中来回移动来实现的，ConditionQueue维护了一个等待信号的队列，
 * 并在适时的时候将节点加入AQS队列中，实现唤醒操作 (signal signalAll)
 */
@Slf4j
public class ReentrantLockConditionExample6 {

    public static void main(String[] args) {
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition = reentrantLock.newCondition();

        //线程1
        new Thread(() -> {
            try {
                //线程加入AQS的等待队列
                reentrantLock.lock();
                log.info("wait signal"); // 1
                //condition.await()，线程从AQS的队列移除，即锁的释放 ，然后加入了ConditionQueue中
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("get signal"); // 4
            reentrantLock.unlock();
        }).start();

        //线程2
        new Thread(() -> {
            //线程2得到锁加入AQS的等待队列
            reentrantLock.lock();
            log.info("get lock"); // 2
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //线程2调用发送信号方法，然后把ConditionQueue中的线程1的节点取出，加入了AQS的等待队列中 （注意此时线程1并没有被唤醒）
            condition.signalAll();
            log.info("send signal ~ "); // 3
            //线程2的锁被释放，线程1此时已经在AQS的队列中，会被按照从头到尾的顺序被唤醒
            reentrantLock.unlock();
        }).start();
    }
}
